# React DOM

This package exports React bindings for the `@floating-ui/dom`
package — a library that provides “anchored positioning” for a
floating element to position it next to a given reference
element.

```shell
npm install @floating-ui/react-dom
```

If you want to build interactions for floating elements easily,
in addition to the positioning, check out
[React DOM Interactions](/docs/react-dom-interactions).

## Usage

`useFloating(){:js}` wraps `computePosition(){:js}` and accepts
all of its [options](/docs/computePosition#options). The most
basic usage is the following:

```js
import {useFloating} from '@floating-ui/react-dom';

function App() {
  const {x, y, reference, floating, strategy} = useFloating();

  return (
    <>
      <button ref={reference}>Button</button>
      <div
        ref={floating}
        style={{
          position: strategy,
          top: y ?? '',
          left: x ?? '',
        }}
      >
        Tooltip
      </div>
    </>
  );
}
```

This will position the floating `Tooltip` element at the **bottom
center** of the `Button` element by default.

- `x{:.const}` and `y{:.const}` are the positioning coordinates.
  These values are `null{:js}` initially, before the layout
  effect has fired (i.e. SSR).
- `reference{:.const}` and `floating{:.const}` are callback refs,
  not regular refs. This allows the position to be updated when
  either elements change (e.g. conditional rendering).
- `strategy{:.const}` is a string, `'absolute'{:js}` (default) or
  `'fixed'{:js}`

To customize the positioning, view the
[computePosition options](/docs/computePosition#options).
Example:

```js
import {
  useFloating,
  offset,
  flip,
  shift,
} from '@floating-ui/react-dom';

useFloating({
  placement: 'right',
  strategy: 'fixed',
  middleware: [offset(10), flip(), shift()],
});
```

## Updating

`useFloating(){:js}` only calculates the position **once** on
render, or when the reference/floating elements changed — for
example, the floating element gets mounted via conditional
rendering.

If the floating element lives in a different `offsetParent`
context to the reference element, it will need to be updated
while mounted to remain “anchored”. This includes scrolling and
resizing the window or the elements themselves.

To do so, use the [autoUpdate](/docs/autoUpdate) utility:

```js
import {useFloating, autoUpdate} from '@floating-ui/react-dom';

function App() {
  useFloating({
    whileElementsMounted: autoUpdate,

    // Or, pass options. Ensure the cleanup function is returned.
    whileElementsMounted: (reference, floating, update) =>
      autoUpdate(reference, floating, update, {
        animationFrame: true,
      }),
  });
}
```

`whileElementsMounted{:.objectKey}` is a fully reactive callback
prop to handle mounting/unmounting of the elements.

> `autoUpdate` is expensive and should only be called when both
> the reference and floating elements are mounted. If your
> floating element is NOT conditionally rendered, and instead
> relies of `visibility` for instance, use an effect instead of
> this prop.

Alternatively (or additionally), you may want to update manually
in some cases. The hook returns an `update(){:js}` function to
update the position at will:

```js
const {update} = useFloating();
```

### Stable ref props

A state update occurs inside the callback ref to ensure the
position is fresh when the element mounts. If the ref prop is not
stable, this results in an infinite loop
[because React calls unstable callback refs thinking it's a new function on each render](https://github.com/facebook/react/issues/6249#issuecomment-195412139).

If you want to merge another ref with the one returned from
`useFloating(){:js}`, memo the value:

```js
// No infinite loop!
const stableRef = useMemo(
  () => mergeRefs([userRef, reference]),
  [userRef, reference]
);

return <div ref={stableRef} />;
```

## External reference

As `reference{:.const}` is a callback ref, you can call it with
your external reference element:

```js /triggerElement/1-3
function MyComponent({triggerElement}) {
  const {reference} = useFloating();

  useLayoutEffect(() => {
    reference(triggerElement);
  }, [triggerElement]);
}
```

The element should be stored in state rather than a plain ref to
ensure reactive updating when it changes.

You may instead want to utilize the `children` prop as the
reference, and attach the ref via `cloneElement(){:js}`. This
also co-locates the reference with the floating component.

```js
cloneElement(children, {ref: reference});
```

## Internal refs

As mentioned previously, `reference{:.const}` and
`floating{:.const}` are callback refs to handle conditional
rendering. They aren't suitable for usage as regular refs.
Instead, access `refs{:.const}`:

```js
const {refs} = useFloating();

// Accessing them inside effects or event handlers:
refs.floating.current;
refs.reference.current;
```

If another library's hook requires a `ref{:.objectKey}` passed to
it, you can do so:

```js
const {refs} = useFloating();
const otherLib = useOtherLib({
  ref: refs.floating, // or refs.reference
});
```

## Arrow

A ref can be passed as the `element{:.objectKey}`:

```js /arrowRef/ {13}
import {useRef} from 'react';
import {useFloating, arrow} from '@floating-ui/react-dom';

function App() {
  const arrowRef = useRef(null);
  const {
    x,
    y,
    reference,
    floating,
    middlewareData: {arrow: {x: arrowX, y: arrowY} = {}},
  } = useFloating({
    middleware: [arrow({element: arrowRef})],
  });

  return (
    <>
      <button ref={reference}>My button</button>
      <div ref={floating}>
        My tooltip
        <div ref={arrowRef} />
      </div>
    </>
  );
}
```

### Arrow styles

In the tutorial, it shows you how to
[style the arrow](https://floating-ui.com/docs/tutorial#arrow-middleware).

This styling relies on the **final** (or resultant) placement,
which can be different from the preferred one you passed as an
option to `useFloating(){:js}` (if you're using `flip(){:js}` or
`autoPlacement(){:js}` middleware).

This final placement gets returned from the hook to enable the
static side position style:

```js
const {placement} = useFloating();
```

### Conditional rendering

In some cases, you might be conditionally rendering the arrow
element (not just the floating element). For instance, you're
demoing a `showArrow={boolean}{:js}` prop for a component while
it's mounted.

Utilize the same technique as the reference and floating elements
which is a callback function that calls `update(){:js}` after
assigning the ref value.

```js /update/
const arrowRef = useRef();
const {update} = useFloating();
const arrowCallback = useCallback(
  (node) => {
    arrowRef.current = node;
    update();
  },
  [update]
);

<div ref={arrowCallback} />;
```

## Virtual Element

See [Virtual Elements](/docs/virtual-elements) for details.

```js {10-16}
import {useLayoutEffect} from 'react';
import {useFloating, shift} from '@floating-ui/react-dom';

function App() {
  const {x, y, reference, floating, strategy} = useFloating();

  useLayoutEffect(() => {
    // Call reference with the virtual element inside an effect
    // or event handler.
    reference({
      getBoundingClientRect() {
        return {
          // ...
        };
      },
    });
  }, [reference]);

  return (
    <div
      ref={floating}
      style={{
        position: strategy,
        top: y ?? '',
        left: x ?? '',
      }}
    >
      Tooltip
    </div>
  );
}
```

## Variables inside middleware functions

To support React Fast Refresh, the hook uses a deepEqual utility
function to ensure the position is updated whenever middleware
change. Function options are compared as strings.

As a result, variables are not "fresh" inside functions passed to
middleware as an option. Instead, use a ref to access data inside
them.

```js
const [n, setN] = useState(10);
const nRef = useRef(10);

useFloating({
  middleware: [
    offset(() => {
      // This won't work
      return n;
      // This will work
      return nRef.current;
    }),
  ],
});
```

Passing it inside the current component scope works as expected:

```js
useFloating({
  middleware: [offset(n)],
});
```

## Testing

The position of your floating element is computed asynchronously,
so a state update occurs during a Promise microtask.

The state update happens **after** your test completes, resulting
in an act warning like this:

```
Warning: An update to App inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
```

There are a couple of ways to fix this:

1. Explicitly call `cleanup(){:js}` at the end of your test if
   you don't care about the positioning:

```js /cleanup/
import {render, cleanup, screen} from '@testing-library/react';

test('example', () => {
  render(<Tooltip content="hello" open />);
  expect(screen.getByRole('tooltip').textContent).toBe('hello');

  // The positioning does not matter
  cleanup();
});
```

2. Flush the microtask queue before the test finishes. This also
   allows you to ensure the floating element has been
   successfully positioned.

```js
test('example', async () => {
  render(<Tooltip open />);
  await act(async () => {});
  // Position is ready, and `act` warning is gone!
});
```

## Types

The `useFloating(){:js}` hook is generic to allow specifying a
narrower reference type. By default, the reference type is wide,
allowing `Element | VirtualElement | null{:js}`.

Due to the `VirtualElement{:.class}` type, you couldn't check if
the reference element contains another node for example.

To fix this, you can pass a generic argument to the hook the
specify a more specific type for the reference:

```tsx {5,11}
import {useFloating, shift} from '@floating-ui/react-dom';

function App() {
  const {reference, floating, refs} =
    useFloating<HTMLButtonElement>({
      placement: 'right',
      middleware: [shift()],
    });

  useEffect(() => {
    if (refs.reference.current?.contains(anotherElement)) {
      // do something
    }
  }, [refs.reference]);

  return (
    <>
      <button ref={reference}>Button</button>
      <div ref={floating}>Tooltip</div>
    </>
  );
}
```
